#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <malloc.h>
#include <stdlib.h>

#include "interaction.h"
#include "ticket_device.h"
#include "list.h"
#include "log.h"

static int read_ticket_file(struct list_head *ticket_head);
static int write_ticket_file(struct list_head *ticket_head);
static int read_user_ticket_file(struct list_head *user_ticket_head);
static int write_user_ticket_file(struct list_head *user_ticket_head);

/**
 * @brief   车票链表初始化
 * @param   ticket_head:包含所有车票信息的指针
 *          user_ticket_head:包含所有用户的车票信息的指针
 * @return  MALLOC_ERROR:申请内存失败
 *          true:正常运行
 *          false:读取文件失败
 */
int ticket_init(struct list_head *ticket_head,
                struct list_head *user_ticket_head)
{
    int ret;

    init_list_head(ticket_head);
    init_list_head(user_ticket_head);

    /*文件操作*/
    ret = read_ticket_file(ticket_head);
    if (ret != true) {
        DEBUG("READ TICKET FILE ERROR!");
        return false;
    }

    ret = read_user_ticket_file(user_ticket_head);
    if (ret != true) {
        DEBUG("READ TICKET FILE ERROR!");
        return false;
    }

    return true;
}

/**
 * @brief   车票链表销毁
 * @param   ticket_head:包含所有车票信息的指针
 *          user_ticket_head:包含所有用户的车票信息的指针
 * @return  true:正常运行
 *          false:读取文件失败
 */
int ticket_destroy(struct list_head *ticket_head,
                    struct list_head *user_ticket_head)
{
    struct list_head *ticket_pos, *user_ticket_pos, *n, *m;
    struct ticket *ticket_free;
    struct user_ticket *user_ticket_free;
    int ret;

    ret = write_ticket_file(ticket_head);
    if (ret != true) {
        DEBUG("WRITE TICKET FILE ERROR!");
        return false;
    }
    ret = write_user_ticket_file(user_ticket_head);
    if (ret != true) {
        DEBUG("WRITE USER TICKET FILE ERROR!");
        return false;
    }

    list_for_each_safe (ticket_pos, n, ticket_head) {
        list_del(ticket_pos);
        ticket_free = list_entry(ticket_pos, struct ticket, list);
        free(ticket_free);
    }

    ticket_pos = NULL;
    n = NULL;
    ticket_free = NULL;
    list_for_each_safe (user_ticket_pos, m, user_ticket_head) {
        list_del(user_ticket_pos);
        user_ticket_free = list_entry(user_ticket_pos,
                                        struct user_ticket, list);
        list_for_each_safe (ticket_pos, n,
                            &user_ticket_free->someone_ticket_head) {
            list_del(ticket_pos);
            ticket_free = list_entry(ticket_pos, struct ticket, list);
            free(ticket_free);
        }
        free(user_ticket_free);
    }

    return true;
}

/**
 * @brief   检测车票信息是否重复
 * @param   ticket_head:车票信息链表的头指针
 *          need_add_ticket:需要
 * @return  ticket_head
 */
int ticket_repeat_check(struct list_head *ticket_head,
                        struct ticket *need_add_ticket)
{
    if (!ticket_head || !need_add_ticket) {
        DEBUG("PARAM ERROR!\n");
        return PARAM_ERROR;
    }

    struct list_head *pos;
    struct ticket *scan_list;

    list_for_each (pos, ticket_head) {
        scan_list = list_entry(pos, struct ticket, list);
        if (!strcmp(scan_list->train_number, need_add_ticket->train_number)) {
            if (!strcmp(scan_list->origin_place, need_add_ticket->origin_place) &&
                !strcmp(scan_list->destination, need_add_ticket->destination) &&
                !strcmp(scan_list->departure_time, need_add_ticket->departure_time) &&
                !strcmp(scan_list->arrival_time, need_add_ticket->arrival_time) &&
                !strcmp(scan_list->price, need_add_ticket->price)) {
                /*进行车票叠加*/
                return TICKET_INFO_REPEAT;
            } else {
                return TRAIN_NUM_REPEAT;
            }
        } else {
            if (!strcmp(scan_list->origin_place, need_add_ticket->origin_place) &&
                !strcmp(scan_list->destination, need_add_ticket->destination)) {
                if (!strcmp(scan_list->departure_time, need_add_ticket->departure_time) ||
                    !strcmp(scan_list->arrival_time, need_add_ticket->arrival_time)) {
                    return PLACE_TIME_REPEAT;
                } else {
                    break;
                }
            }
        }
    }

    return true;
}

/**
 * @brief   将车票信息加入当前用户的车票链表中
 * @param   current_user_ticket:指向用户的车票信息的链表的当前用户的节点的指针
 *          buy_ticket:指向购买的车票的节点
 */
int add_user_ticket(struct list_head **current_user_ticket_head,
                        struct ticket *buy_ticket)
{
    if (!buy_ticket) {
        DEBUG("PARAM ERROR!\n");
        return PARAM_ERROR;
    }
    
    struct ticket *new_list = NULL, *scan_list;
    struct list_head *pos;
    int ret = NO_THIS_TICKET;

    list_for_each (pos, *current_user_ticket_head) {
        scan_list = list_entry(pos, struct ticket, list);
        if (!strcmp(scan_list->train_number, buy_ticket->train_number)) {
            sprintf(scan_list->ticket_number, "%d",
                        atoi(scan_list->ticket_number) + 1);
            return true;
        } else {
            ret = NO_THIS_TICKET;
        }
    }

    if (ret == NO_THIS_TICKET) {
        printf("NO_THIS_TICKET\n");
        new_list = (struct ticket *)calloc(1, sizeof(struct ticket));
        if (!new_list) {
            DEBUG("MALLOC ERROR!\n");
            return MALLOC_ERROR;
        }

        strncpy(new_list->origin_place, buy_ticket->origin_place,
                                        sizeof(buy_ticket->origin_place));
        strncpy(new_list->destination, buy_ticket->destination,
                                        sizeof(buy_ticket->destination));
        strncpy(new_list->departure_time, buy_ticket->departure_time,
                                        sizeof(buy_ticket->departure_time));
        strncpy(new_list->arrival_time, buy_ticket->arrival_time,
                                        sizeof(buy_ticket->arrival_time));
        strncpy(new_list->train_number, buy_ticket->train_number,
                                        sizeof(buy_ticket->train_number));
        strncpy(new_list->price, buy_ticket->price,
                                        sizeof(buy_ticket->price));
        strncpy(new_list->ticket_number, "1", 1);

        list_add_tail(&new_list->list, *current_user_ticket_head);
    }

    return true;
}

/**
 * @brief   删除用户购买的车票
 * @param   train_number:想要删除的车票的车次
 *          current_user_ticket_head:当前用户的车票链表的头文件
 * @return  false:没有购买过这个车次
 *          true:删除成功
 */
int delete_user_ticket(char *train_number,
                        struct list_head *current_user_ticket_head)
{
    if (!train_number) {
        DEBUG("PARAM ERROR!\n");
        return PARAM_ERROR;
    }

    struct list_head *pos ,*n;
    struct ticket *scan_list;

    list_for_each_safe (pos, n, current_user_ticket_head) {
        scan_list = list_entry(pos, struct ticket, list);
        if (!strcmp(scan_list->train_number, train_number)) {
            list_del(pos);
            free(scan_list);
            return true;
        }
    }

    return false;
}

/**
 * @brief   将车票数据从文件中读出来
 * @param   ticket_head：车票数据的头指针
 * @return  传参错误、打开文件错误、malloc错误等一系列错误返回false
 *          正确运行返回true
 */
static int read_ticket_file(struct list_head *ticket_head)
{
    char origin_place[ORIGIN_PLACE_SIZE];
    char destination[DESTINATION_SIZE];
    struct ticket *temp = NULL;
    FILE *save_file;

    /* 打开文件 */
    save_file = fopen("./lib/ticket_data.txt", "a+");
    if (!save_file) {
        save_file = fopen("../.././lib/ticket_data.txt", "a+");
        if (!save_file) {
            DEBUG("FAIL TO OPEN TICKET DATA FILE\n");
            return false;
        }
    }

    temp = (struct ticket *)malloc(sizeof(struct ticket));
    if (!temp) {
        DEBUG("FAIL TO MALLOC\n");
        fclose(save_file);
        return false;
    }

    /* 先把数据读取到temp里面 */
    fscanf(save_file, "%20s\t%20s\t%3s\t%7s\t%7s\t%3s\t%3s",
                        origin_place, destination,
                        temp->train_number,
                        temp->departure_time,
                        temp->arrival_time,
                        temp->price, temp->ticket_number);

    strncpy(temp->origin_place, origin_place, sizeof(origin_place));
    strncpy(temp->destination, destination, sizeof(destination));

    /* 将节点接入链表 */
    while (!feof(save_file)) {
        list_add_tail(&temp->list, ticket_head);

        temp = (struct ticket *)
                    malloc(sizeof(struct ticket));
        if (!temp) {
            DEBUG("FAIL TO MALLOC\n");
            return false;
        }

        fscanf(save_file, "%20s\t%20s\t%3s\t%7s\t%7s\t%3s\t%3s",
                        origin_place, destination,
                        temp->train_number,
                        temp->departure_time,
                        temp->arrival_time,
                        temp->price, temp->ticket_number);

        strncpy(temp->origin_place, origin_place, sizeof(origin_place));
        strncpy(temp->destination, destination, sizeof(destination));
    }

    free(temp);
    fclose(save_file);
    return true;
}

/**
 * @brief   将车票数据写入文件中
 * @param   ticket_head：车票数据的头指针
 * @return  传参错误、打开文件错误返回false
 *          正确运行返回true
 */
static int write_ticket_file(struct list_head *ticket_head)
{
    if (!ticket_head) {
        DEBUG("PARAM ERROR\n");
        return false;
    }

    struct ticket *scan_list;
    struct list_head *pos;
    FILE *save_file;

    /* 打开文件 */
    save_file = fopen("./lib/ticket_data.txt", "w");
    if (!save_file) {
        save_file = fopen("../.././lib/ticket_data.txt", "w");
        if (!save_file) {
            DEBUG("FAIL TO OPEN TICKET DATA FILE\n");
            return false;
        }
    }

    /* 将链表中的数据依次写入文件 */
    list_for_each (pos, ticket_head) {
        scan_list = list_entry(pos, struct ticket, list);
        fprintf(save_file, "%s\t%s\t%s\t%s\t%s\t%s\t%s\n",
                            scan_list->origin_place,
                            scan_list->destination,
                            scan_list->train_number,
                            scan_list->departure_time,
                            scan_list->arrival_time, 
                            scan_list->price,
                            scan_list->ticket_number);
    }

    fclose(save_file);
    return true; 
}

/**
 * @brief   将用户的车票数据从文件中读出来
 * @param   user_ticket_head：用户的车票数据的头指针
 * @return  传参错误、打开文件错误返回false
 *          正确运行返回true
 */
static int read_user_ticket_file(struct list_head *user_ticket_head)
{
    struct ticket *temp = NULL;
    struct user_ticket *new_list;
    int type_num;
    FILE *save_file;
    char origin_place[ORIGIN_PLACE_SIZE];
    char destination[DESTINATION_SIZE];

    /* 打开文件 */
    save_file = fopen("./lib/user_ticket_data.txt", "a+");
    if (!save_file) {
        save_file = fopen("../.././lib/user_ticket_data.txt", "a+");
        if (!save_file) {
            DEBUG("FAIL TO OPEN USER TICKET DATA FILE\n");
            return false;
        }
    }

    fscanf(save_file, "%d", &type_num);

    while (!feof(save_file)) {
        new_list = (struct user_ticket *)malloc
                                        (sizeof(struct user_ticket));
        init_list_head(&new_list->someone_ticket_head);
        list_add_tail(&new_list->list, user_ticket_head);

        if (!type_num) {
            fscanf(save_file, "%d", &type_num);
            continue;
        } else {
            while (type_num > 0) {
                temp = (struct ticket *)malloc(sizeof(struct ticket));
                if (!temp) {
                    DEBUG("FAIL TO MALLOC\n");
                    return false;
                }
                
                fscanf(save_file, "%20s\t%20s\t%3s\t%7s\t%7s\t%3s\t%3s",
                                        origin_place, destination,
                                        temp->train_number,
                                        temp->departure_time,
                                        temp->arrival_time,
                                        temp->price,
                                        temp->ticket_number);
                strncpy(temp->origin_place, origin_place,
                                            sizeof(origin_place));
                strncpy(temp->destination, destination,
                                            sizeof(destination));
                type_num--;

                list_add_tail(&temp->list,
                                    &new_list->someone_ticket_head);
            }
            fscanf(save_file, "%d", &type_num);
        }
    }

    fclose(save_file);
    return true;
}

/**
 * @brief   将用户的车票数据写入文件中
 * @param   user_ticket_head：用户的车票数据的头指针
 * @return  传参错误、打开文件错误返回false
 *          正确运行返回true
 */
static int write_user_ticket_file(struct list_head *user_ticket_head)
{
    struct list_head *pos1, *pos2;
    struct user_ticket *scan_list;
    struct ticket *user_ticket;
    int type_num;
    FILE *save_file;

    /* 打开文件 */
    save_file = fopen("./lib/user_ticket_data.txt", "w");
    if (!save_file) {
        save_file = fopen("../.././lib/user_ticket_data.txt", "w");
        if (!save_file) {
            DEBUG("FAIL TO OPEN USER TICKET DATA FILE\n");
            return false;
        }
    }

    list_for_each (pos1, user_ticket_head) {
        type_num = 0;
        scan_list = list_entry(pos1, struct user_ticket, list);

        list_for_each (pos2, &scan_list->someone_ticket_head) {
            type_num++;
        }
        fprintf(save_file, "%d\n", type_num);

        pos2 = NULL;
        list_for_each (pos2, &scan_list->someone_ticket_head) {
            user_ticket = list_entry(pos2, struct ticket, list);
            fprintf(save_file, "%s\t%s\t%s\t%s\t%s\t%s\t%s\n",
                            user_ticket->origin_place,
                            user_ticket->destination,
                            user_ticket->train_number,
                            user_ticket->departure_time,
                            user_ticket->arrival_time,
                            user_ticket->price,
                            user_ticket->ticket_number);
        }
    }

    fclose(save_file);
    return true;
}